## MessageCenter 自动加载单例
## 在 Godot 项目设置中添加为 AutoLoad：
## 项目 -> 项目设置 -> AutoLoad -> 添加此脚本，命名为 "MessageCenter"
##
## 使用方式：
## MessageCenter.send(self, "player_died", {"score": 100})
## MessageCenter.subscribe(self, "player_died", _on_player_died)

extends Node

# 订阅字典: {channel_name: [Subscription, ...]}
var _subscriptions: Dictionary = {}
var _anonymous_id: int = 0


## 发送消息到指定频道
func send(sender, channel: String, data = null) -> void:
	if sender == null:
		push_error("MessageCenter.send: sender cannot be null")
		return
	
	if channel.is_empty():
		push_error("MessageCenter.send: channel cannot be empty")
		return
	
	_inner_send(sender, channel, data)


func _inner_send(sender, channel: String, data) -> void:
	if not _subscriptions.has(channel):
		return
	
	var subscription_list = _subscriptions[channel]
	var invalid_subscriptions = []
	
	for subscription in subscription_list.duplicate():
		if subscription != null:
			# 尝试调用，如果返回false说明订阅源已失效
			if not subscription.invoke(sender, data):
				invalid_subscriptions.append(subscription)
	
	# 清理已失效的订阅
	if invalid_subscriptions.size() > 0:
		_clean_invalid_subscriptions(channel, invalid_subscriptions)


## 订阅消息频道
## @param subscriber: 订阅者对象
## @param channel: 频道名称
## @param callback: 回调函数（Callable）
## @param params_count: 参数数量 (1 或 2)
func subscribe(subscriber, channel: String, callback, params_count: int = 2) -> void:
	if subscriber == null:
		push_error("MessageCenter.subscribe: subscriber cannot be null")
		return
	
	if channel.is_empty():
		push_error("MessageCenter.subscribe: channel cannot be empty")
		return
	
	if callback == null:
		push_error("MessageCenter.subscribe: callback cannot be null")
		return
	
	_inner_subscribe(subscriber, channel, callback, params_count)


## 匿名订阅
func subscribe_anonymous(channel: String, callback, params_count: int = 2):
	_anonymous_id += 1
	var anonymous_subscriber = "AnonymousSubscriber_" + str(_anonymous_id)
	_inner_subscribe(anonymous_subscriber, channel, callback, params_count)
	return anonymous_subscriber


func _inner_subscribe(subscriber, channel: String, callback, params_count: int) -> void:
	var subscription = Subscription.new(subscriber, callback, params_count)
	
	if _subscriptions.has(channel):
		_subscriptions[channel].append(subscription)
	else:
		_subscriptions[channel] = [subscription]


## 取消订阅
func unsubscribe(subscriber, channel: String) -> void:
	if not _subscriptions.has(channel):
		return
	
	var subscription_list = _subscriptions[channel]
	
	# 使用 or 而非 and（修复C#版本bug）
	if subscription_list == null or subscription_list.size() == 0:
		_subscriptions.erase(channel)
		return
	
	_subscriptions[channel] = subscription_list.filter(
		func(sub): return sub.get_source() != subscriber
	)
	
	if _subscriptions[channel].size() == 0:
		_subscriptions.erase(channel)


## 取消所有订阅
func unsubscribe_all(subscriber) -> void:
	var channels_to_remove = []
	
	for channel in _subscriptions.keys():
		var subscription_list = _subscriptions[channel]
		_subscriptions[channel] = subscription_list.filter(
			func(sub): return sub.get_source() != subscriber
		)
		
		if _subscriptions[channel].size() == 0:
			channels_to_remove.append(channel)
	
	for channel in channels_to_remove:
		_subscriptions.erase(channel)


## 清理失效的订阅（内部方法）
func _clean_invalid_subscriptions(channel: String, invalid_subs: Array) -> void:
	if not _subscriptions.has(channel):
		return
	
	var subscription_list = _subscriptions[channel]
	
	for invalid_sub in invalid_subs:
		subscription_list.erase(invalid_sub)
	
	if subscription_list.size() == 0:
		_subscriptions.erase(channel)


## 获取频道订阅数量
func get_subscription_count(channel: String) -> int:
	if not _subscriptions.has(channel):
		return 0
	return _subscriptions[channel].size()


## 检查频道是否存在订阅
func has_subscriptions(channel: String) -> bool:
	return _subscriptions.has(channel) and _subscriptions[channel].size() > 0


## 清空所有订阅
func clear_all() -> void:
	_subscriptions.clear()


## 获取所有频道
func get_all_channels() -> Array:
	return _subscriptions.keys()


## 调试打印
func debug_print_subscriptions() -> void:
	print("=== MessageCenter Subscriptions ===")
	for channel in _subscriptions.keys():
		print("Channel: ", channel, " - Subscribers: ", _subscriptions[channel].size())
	print("===================================")


# Subscription 内部类
class Subscription:
	var id: String
	var source_ref: WeakRef  # 弱引用，避免内存泄漏
	var callback: Callable
	var params_count: int
	
	func _init(src, cb, pcount: int = 2):
		self.id = str(Time.get_ticks_usec()) + "_" + str(randi())
		
		if src == null:
			push_error("Subscription: source cannot be null")
			return
		
		if cb == null:
			push_error("Subscription: callback cannot be null")
			return
		
		# 为字符串类型创建特殊处理（匿名订阅者）
		if src is String:
			self.source_ref = null
		else:
			self.source_ref = weakref(src)
		
		self.callback = cb
		self.params_count = pcount
	
	## 获取订阅源对象
	func get_source():
		if source_ref == null:
			return null
		return source_ref.get_ref()
	
	## 检查订阅源是否仍然有效
	func is_valid() -> bool:
		if source_ref == null:
			return false
		return get_source() != null
	
	func invoke(sender, data) -> bool:
		if sender == null:
			return false
		
		if not is_valid():
			return false
		
		if callback == null:
			push_error("Subscription.invoke: callback is null")
			return false
		
		if params_count == 1:
			if callback is Callable:
				callback.call(sender)
		else:
			if callback is Callable:
				callback.call(sender, data)
		
		return true
